/**
    ATClab - scriptable Air Traffic Control simulations.
    Copyright (C) 2010 openatclab@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/

#include "canvas_infoblock.h"

#include "atc.h"
#include "canvas.h"
#include "presenter.h"

using namespace atc;

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// InfoBlock : QCanvasText
//
//--------------------------------------------------------------------------------------------------
// class
//

const QPen InfoBlock::BORDER_PEN( Qt::black, 2 );


//--------------------------------------------------------------------------------------------------
// construction
//

/*!
 *
 */
InfoBlock::InfoBlock( Canvas *canvas, const QString &text)
		: QObject( canvas )
		, _canvas( canvas )
		, _display( new Q3CanvasText( text, CANVAS_FONT, canvas ) )
{	

	QRect rect = _display->boundingRect();
	rect.setWidth(rect.width() * 1.44); // font adjustment hack
	_border = new Q3CanvasRectangle(rect, canvas);
	_border->setPen( BORDER_PEN );
}

/*!
 *
 */
InfoBlock::~InfoBlock() {}

//--------------------------------------------------------------------------------------------------
// 
//

/*!
 *
 */
void InfoBlock::move( const QPoint &p ) {
	_display->move( p.x() + 10, p.y() );
	_border->move( p.x() + 8, p.y() );
	update();
}

/*!
 *
 */
void InfoBlock::setVisible( bool visible ) {
	_display->setVisible( visible );
	_border->setVisible( visible );
	update();
}


////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ClockDisplay : InfoBlock
//
//--------------------------------------------------------------------------------------------------
// class
//

const QColor ClockDisplay::STOP_COLOUR( Qt::red );
const QColor ClockDisplay::RUN_COLOUR( Qt::darkMagenta );
const QString ClockDisplay::INITIAL_TEXT( "  --:--:--  " );
const QString ClockDisplay::FORMAT_TEXT( "  %02d:%02d:%02d " );


//--------------------------------------------------------------------------------------------------
// construction
//

/*!
 *
 */
ClockDisplay::ClockDisplay( Canvas *canvas ) 
		: InfoBlock( canvas, INITIAL_TEXT )
{
	_display->setColor( RUN_COLOUR );
	connect( canvas, SIGNAL( sig_update_clock(long) ), this, SLOT( update_clock(long) ) );
	connect( canvas, SIGNAL( sig_stop_clock() ), this, SLOT( update_stop() ) );
	connect( canvas, SIGNAL( sig_start_clock() ), this, SLOT( update_start() ) );
}

/*!
 *
 */
ClockDisplay::~ClockDisplay() {}


//--------------------------------------------------------------------------------------------------
// [public slots]
//

/*!
 *
 */
void ClockDisplay::update_clock( long seconds ) {
	int s = seconds % SIXTY;
	int m = seconds / SIXTY;
	int h =       m / SIXTY;
		m =       m % SIXTY;

	_display->setText( QString().sprintf( FORMAT_TEXT, h,m,s ) );
	update();
}

/*!
 *
 */
void ClockDisplay::update_stop() {
	_display->setColor( STOP_COLOUR );
	update();
}

/*!
 *
 */
void ClockDisplay::update_start() {
	_display->setColor( RUN_COLOUR );
	update();
}



////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ScoreDisplay : InfoBlock
//
//--------------------------------------------------------------------------------------------------
// class
//

const QColor ScoreDisplay::COLOUR( Qt::darkGreen );
const QString ScoreDisplay::INITIAL_TEXT( "Penalty: ---" );
const QString ScoreDisplay::FORMAT_TEXT ( "Penalty: %03d" );


//--------------------------------------------------------------------------------------------------
// construction
//
	
/*!
 *
 */
ScoreDisplay::ScoreDisplay( Canvas *canvas ) 
		: InfoBlock( canvas, INITIAL_TEXT )
{
	_display->setColor( COLOUR );
	connect( canvas, SIGNAL( sig_update_score(long) ), this, SLOT( update_score(long) ) );
	connect( canvas, SIGNAL( update_score_quietly(long) ), this, SLOT( update_score_quietly(long) ) );
}
	
/*!
 *
 */
ScoreDisplay::~ScoreDisplay() {}

//--------------------------------------------------------------------------------------------------
// [public slots]
//

/*!
 *
 */
void ScoreDisplay::update_score( long score ) {
	update_score_quietly(score);
}

/*!
 *
 */
void ScoreDisplay::update_score_quietly( long score ) {
	_display->setText( QString().sprintf( FORMAT_TEXT, score ) );
	update();
}


////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GoalDisplay : InfoBlock
//
//--------------------------------------------------------------------------------------------------
// class
//

const QColor GoalDisplay::COLOUR( Qt::darkRed );
const QString GoalDisplay::INITIAL_TEXT( "Goal   : ---" );
const QString GoalDisplay::FORMAT_TEXT ( "Goal   : %03d" );


//--------------------------------------------------------------------------------------------------
// construction
//
	
/*!
 *
 */
GoalDisplay::GoalDisplay( Canvas *canvas,
						 const std::string& a_label,
						 const std::string& a_globalRef,
						 const std::string& a_text) 
	:	InfoBlock(canvas, INITIAL_TEXT),
		m_label(a_label),
		m_globalRef(a_globalRef),
		m_text(a_text)
{
	_display->setColor(COLOUR);
	_display->setFont(QFont( "Courier New", 24, QFont::Bold));
	//connect( canvas, SIGNAL( sig_update_goal(long) ), this, SLOT( update_goal(long) ) );
	
	_display->setText(GetDisplayString());
	update();
}
	
/*!
 *
 */
GoalDisplay::~GoalDisplay() {}

//--------------------------------------------------------------------------------------------------
// [public slots]
//

/*!
 *
 */
void 
GoalDisplay::update_goal( long goal ) 
{
	std::stringstream str;

	str << m_label << goal << m_text;
	QString formattedText(str.str().c_str());

	_display->setText(formattedText);
	update();
}

QString
GoalDisplay::GetDisplayString() const
{
	QString display;

	if (m_label != "")
	{
		std::stringstream str;
		str << m_label;

		pact::Presenter *p = pact::Presenter::instance();
		pact::GlobalVariables vars = p->globals();
		pact::GlobalVariables::iterator vit = vars.find(m_globalRef);

		if (vit != vars.end())
		{
			str << " " << vit->second->value() << " " << m_text;
		}

		display = str.str().c_str();
	}
	else
	{
		/** old style goal display **/

		_display->setFont(QFont( "Courier New", 45, QFont::Bold));

		pact::Presenter *p = pact::Presenter::instance();
		pact::GlobalVariables vars = p->globals();
		pact::GlobalVariables::iterator vit = vars.find("goal");

		if (vit != vars.end())
		display = QString().sprintf(FORMAT_TEXT, vit->second->value());
	}

	return display;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GenericDisplay : InfoBlock
//
//--------------------------------------------------------------------------------------------------
// class
//

const QColor GenericDisplay::COLOUR( Qt::darkRed );
const QString GenericDisplay::INITIAL_TEXT( "" );
const QString GenericDisplay::FORMAT_TEXT ( "" );


//--------------------------------------------------------------------------------------------------
// construction
//
	
GenericDisplay::GenericDisplay( Canvas *canvas,
								const std::string& a_label,
								const std::string& a_globalRef,
								const std::string& a_text) 
	:	InfoBlock(canvas, INITIAL_TEXT),
		m_label(a_label),
		m_globalRef(a_globalRef),
		m_text(a_text)
{
	_display->setColor(COLOUR);
	_border->setSize(484, 75);
	_display->setFont(QFont( "Courier New", 23, QFont::Bold));
	
	pact::Presenter *p = pact::Presenter::instance();
	pact::GlobalVariables vars = p->globals();
	pact::GlobalVariables::iterator vit = vars.find(m_globalRef);

	if (vit != vars.end())
	{
		connect(vit->second, SIGNAL(value_changed(int)), this, SLOT(UpdateDisplay(int)));
	}

	_display->setText(GetDisplayString());
	update();
}

GenericDisplay::~GenericDisplay() {}

void
GenericDisplay::UpdateDisplay(int a_updatedValue)
{
	_display->setText(GetDisplayString());
	update();
}

QString
GenericDisplay::GetDisplayString() const
{
	QString display;

	if (m_label != "")
	{
		std::stringstream str;
		str << m_label;

		pact::Presenter *p = pact::Presenter::instance();
		pact::GlobalVariables vars = p->globals();
		pact::GlobalVariables::iterator vit = vars.find(m_globalRef);

		if (vit != vars.end())
		{
			str << " " << vit->second->value() << " " << m_text;
		}

		display = str.str().c_str();
	}
	else
	{
		display = FORMAT_TEXT;
	}

	return display;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// CorrectDecisionsDisplay : GenericDisplay
//
//--------------------------------------------------------------------------------------------------
// class
//

//--------------------------------------------------------------------------------------------------
// construction
//
CorrectDecisionsDisplay::CorrectDecisionsDisplay(	Canvas *canvas,
													const std::string& a_label,
													const std::string& a_globalRef,
													const std::string& a_text) 
	:	GenericDisplay(canvas, a_label, a_globalRef, a_text)
{
}

CorrectDecisionsDisplay::~CorrectDecisionsDisplay()
{
}


////////////////////////////////////////////////////////////////////////////////////////////////////
//
// IncorrectDecisionResultsDisplay : GenericDisplay
//
//--------------------------------------------------------------------------------------------------
// class
//
//--------------------------------------------------------------------------------------------------
// construction
//
IncorrectDecisionsDisplay::IncorrectDecisionsDisplay(	Canvas *canvas,
														const std::string& a_label,
														const std::string& a_globalRef,
														const std::string& a_text) 
	:	GenericDisplay(canvas, a_label, a_globalRef, a_text)
{
}

IncorrectDecisionsDisplay::~IncorrectDecisionsDisplay()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// SelfReferentGoalDisplay : InfoBlock
//
//--------------------------------------------------------------------------------------------------
// class
//

const QColor SelfReferentGoalDisplay::COLOUR( Qt::darkRed );
const QString SelfReferentGoalDisplay::INITIAL_TEXT( "Self Referent Goal   : ---" );

//--------------------------------------------------------------------------------------------------
// construction
//
SelfReferentGoalDisplay::SelfReferentGoalDisplay( Canvas *canvas ) 
		: InfoBlock( canvas, INITIAL_TEXT )
{
	_display->setColor( COLOUR );
	_display->setFont(QFont( "Courier New", 22, QFont::Bold));
	_border->setSize(484, 150);

	pact::GlobalVariables::iterator vit = 
		pact::Presenter::instance()->globals().find("SRGoal");
	
	if (vit != pact::Presenter::instance()->globals().end())
	{
		update_goal(vit->second->value());
	}
}
	
SelfReferentGoalDisplay::~SelfReferentGoalDisplay() 
{
}

//--------------------------------------------------------------------------------------------------
// [public slots]
//
void 
SelfReferentGoalDisplay::update_goal(long goal) 
{
	std::stringstream display;

	display << "Self Referent Goal:\n";

	if (goal > 0)
	{
		display << "Perform " << goal << " points better\nthan my previous performance";
	}
	else if (goal == 0)
	{
		display << "Perform neither better nor\nworse than my previous\nperformance";
	}
	else if (goal == -1)
	{
		// Don't display anything for an invalid value
	}
	else
	{
		display << "Avoid performing " << abs(goal) << " points\nworse than my previous\nperformance";
	}
	
	_display->setText(display.str().c_str());

	update();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// NormativeGoalDisplay : NormativeGoalDisplay
//
//--------------------------------------------------------------------------------------------------
// class
//

const QColor NormativeGoalDisplay::COLOUR( Qt::darkRed );
const QString NormativeGoalDisplay::INITIAL_TEXT( "Normative Goal   : ---" );

//--------------------------------------------------------------------------------------------------
// construction
//
NormativeGoalDisplay::NormativeGoalDisplay( Canvas *canvas ) 
		: InfoBlock( canvas, INITIAL_TEXT )
{
	_display->setColor( COLOUR );
	_display->setFont(QFont( "Courier New", 22, QFont::Bold));
	_border->setSize(484, 150);

	pact::GlobalVariables::iterator vit = 
		pact::Presenter::instance()->globals().find("NormGoal");
	
	if (vit != pact::Presenter::instance()->globals().end())
	{
		update_goal(vit->second->value());
	}
}
	
NormativeGoalDisplay::~NormativeGoalDisplay() 
{
}


//--------------------------------------------------------------------------------------------------
// [public slots]
//

void 
NormativeGoalDisplay::update_goal(long goal) 
{
	std::stringstream display;

	display << "Normative Goal:\n";

	if (goal > 0)
	{
		display << "Perform " << goal << " points better\nthan previous participants";
	}
	else if (goal == 0)
	{
		display << "Perform neither better nor\nworse than previous\nparticipants";
	}
	else if (goal == -1)
	{
		// Don't display anything for an invalid value
	}
	else
	{
		display << "Avoid performing " << abs(goal) << " points\nworse than previous\nparticipants";
	}

	_display->setText(display.str().c_str());
	update();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// ToolDisplay : InfoBlock
//
//--------------------------------------------------------------------------------------------------
// class
//

const QColor ToolDisplay::COLOUR( Qt::darkBlue );
const QString ToolDisplay::INITIAL_TEXT( "            " );


//--------------------------------------------------------------------------------------------------
// construction
//
	
/*!
 *
 */
ToolDisplay::ToolDisplay( Canvas *canvas ) 
		: InfoBlock( canvas, INITIAL_TEXT )
{
	_display->setColor( COLOUR );

	connect( 
			canvas, SIGNAL( sig_update_tool(const QString &) ), 
			this, SLOT( update_tool(const QString &) ) 
		);
}
	
/*!
 *
 */
ToolDisplay::~ToolDisplay() {}


//--------------------------------------------------------------------------------------------------
// [public slots]
//

/*!
 *
 */
void ToolDisplay::update_tool( const QString &tool ) {
	_display->setText( tool );
	update();
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
